const WebSocket = require("ws");
const fs = require("fs");
const path = require("path");

// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8088 });

// 跟踪每个客户端最后读取的位置（以字节为单位）
const clients = new Map();

// 定义文件路径
const filePath = path.join(
  path.resolve("../"),
  "fileservice/serve_log/log.txt"
);

// 发送文件内容给客户端，并设置正确的初始偏移量
function sendFileContent(ws) {
  fs.readFile(filePath, (err, data) => {
    if (err) {
      console.error("Error reading file:", err);
      ws.send(
        JSON.stringify({
          message_type: "server_error",
          data: {
            error_info: err,
          },
        })
      );
      return;
    }
    const content = data.toString("utf8"); // 将Buffer转换为字符串再发送
    ws.send(
      JSON.stringify({
        message_type: "send_content",
        data: {
          type: 1,
          content: content,
        },
      })
    );
    // 更新该客户端最后读取的位置（以字节为单位）
    clients.set(ws, { offset: Buffer.byteLength(content, "utf8") });
  });
}

// 处理日志文件追加
function handleLogFileAppend() {
  // 遍历所有连接的客户端，发送更新后的新内容
  clients.forEach(({ offset }, ws) => {
    readAndSendUpdatedContent(ws, offset);
  });
}

//广播通知在线连接总量
function sendClinetsConnectNumber() {
  clients.forEach(({ offset }, ws) => {
    ws.send(
      JSON.stringify({
        message_type: "clients_total_number",
        data: {
          connect_number: Array.from(clients).length,
        }
      })
    );
  });
}

// 当有新的客户端连接时触发
wss.on("connection", (ws,req) => {
  clients.set(ws, { offset: 0 });
  console.log(
    `新的连接已建立！,当前在线客户端数量(${Array.from(clients).length}个)`,req.connection.remoteAddress
  );
  //广播通知在线连接总量
  sendClinetsConnectNumber();
  // 初始化新连接的客户端，发送整个文件内容
  sendFileContent(ws);
  // 监听来自客户端的消息（如果需要）
  ws.on("message", (message) => {
    console.log("来自客户端的消息 => ", message);
  });
  // 处理客户端断开连接
  ws.on("close", () => {
    console.log("客户端断开连接");
    clients.delete(ws); // 移除断开连接的客户端
    console.log(Array.from(clients).length)
    sendClinetsConnectNumber();
  });
});

//开启监听日志文件变化通知前端变更
if (fs.existsSync(filePath)) {
  // 使用fs.watch监听文件变化
  fs.watch(filePath, (eventType, filename) => {
    if (filename && eventType === "change") {
      console.log(`日志文件 【${filename}】 内容发生改变`);
      //日志默认不断增加，不能修改删除，需要清理日志发送一个广播消息提前通知已连接的客户端
      handleLogFileAppend();
    }
  });
} else {
  console.log(`${filePath}日志文件不存在了`);
  clients.forEach(({ offset }, ws) => {
    ws.send(
      JSON.stringify({
        message_type: "server_error",
        data: {
          error_info: `${filePath}日志文件不存在了`,
        },
      })
    );
  });
}

// 读取并发送自上次读取以来新增的内容
function readAndSendUpdatedContent(ws, offset) {
  fs.open(filePath, "r", (err, fd) => {
    if (err) {
      console.error("打开文件失败:", err);
      ws.send(
        JSON.stringify({
          message_type: "server_error",
          data: {
            error_info: `打开文件失败:${filePath}`,
          },
        })
      );
      return;
    }

    const chunkSize = 1024 * 10; // 每次读取的最大字节数为10KB
    const buffer = Buffer.alloc(chunkSize);

    fs.read(fd, buffer, 0, chunkSize, offset, (err, bytesRead, buffer) => {
      fs.close(fd, (closeErr) => {
        if (closeErr) {
          console.error("文件关闭失败:", closeErr);
          ws.send(
            JSON.stringify({
              message_type: "server_error",
              data: {
                error_info: `文件关闭失败:${closeErr}`,
              },
            })
          );
        }
      });

      if (err) {
        console.log(`读取文件失败:${err}`);
        ws.send(
          JSON.stringify({
            message_type: "server_error",
            data: {
              error_info: `读取文件失败:${err}`,
            },
          })
        );
        return;
      }

      if (bytesRead > 0) {
        // 发送新内容给客户端
        ws.send(
          JSON.stringify({
            message_type: "send_content",
            data: {
              type: 2,
              content: buffer.toString("utf8", 0, bytesRead),
            },
          })
        );
        // 更新该客户端的偏移量（以字节为单位）
        clients.set(ws, { offset: offset + bytesRead });
      } else {
        console.log("没有新内容要发送");
      }
    });
  });
}

console.log("WebSocket服务器运行在ws://localhost:8088");
